

#ifndef _DESIGN_PATTERN_STRUCTURAL_PROXY_PROXY_H_
#define _DESIGN_PATTERN_STRUCTURAL_PROXY_PROXY_H_

#include "../../test_include.h"

namespace proxy {

class Subject {
 public:
  virtual ~Subject()     = default;
  virtual void Request() = 0;
};

using SubjectSptr = std::shared_ptr<Subject>;

class ConcreteSubject : public Subject {
 public:
  ConcreteSubject() { std::cout << "ConcreteSubject ctor..." << std::endl; };
  ~ConcreteSubject() { std::cout << "ConcreteSubject dtor..." << std::endl; };

  void Request() override {
    std::cout << "ConcreteSubject Request..." << std::endl;
  }
};

class Proxy : public Subject {
 public:
  Proxy() { std::cout << "Proxy ctor..." << std::endl; }
  ~Proxy() { std::cout << "Proxy dtor..." << std::endl; }

  void Request() override {
    std::cout << "Proxy Request..." << std::endl;
    if (nullptr == this->subject_sptr_) {
      this->subject_sptr_ = std::make_shared<ConcreteSubject>();
    }
    this->DoSomething1();
    this->subject_sptr_->Request();
    this->DoSomething2();
  }

  void DoSomething1() { std::cout << "Proxy DoSomething1..." << std::endl; }

  void DoSomething2() { std::cout << "Proxy DoSomething2..." << std::endl; }

 private:
  SubjectSptr subject_sptr_{nullptr};
};

//////////////////////////////////////////////////////////////////////////

void Test() {
  std::cout << std::endl;
  std::cout << "proxy//////////////////////////////////////////////////////////"
               "////////////////"
            << std::endl;
  std::cout << std::endl;

  auto proxy = std::make_shared<Proxy>();
  proxy->Request();
}

}  // namespace proxy

#endif  // _DESIGN_PATTERN_STRUCTURAL_PROXY_PROXY_H_
